home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Interapplication Comm / SnapshotSample / SnapshotSample.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-28  |  11.6 KB  |  415 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        SnapshotSample.c
  3.  
  4.     Contains:    Code for saving and restoring desktop icons.
  5.                 This sample, when run the first time, creates a 
  6.                 snapshot file in the Preferences folder which contains a list 
  7.                 of the names and locations fo the items on the 
  8.                 desktop.
  9.     
  10.                 Running the sample again will read the snapshot
  11.                 file and tell the Finder to position the items
  12.                 at the locations read from the snapshot file.
  13.     
  14.                 Sample does not read/set location of Trash,
  15.                 nor of mounted volumes.
  16.     
  17.                 Sample is provided as is... I didn't get much 
  18.                 chance to test beyond the standard, "oh, this
  19.                 works!" stage.
  20.     
  21.                 The original Pascal version was written by
  22.                 Quinn "The Eskimo!" and released as a Freeware
  23.                 utility.  This DTS sample was created by
  24.                 Deborah Grits.  This version was tidied up
  25.                 and released by Quinn "The Eskimo!".
  26.     
  27.     Oh what a tangled web we weave...
  28.  
  29.     Written by: Quinn "The Eskimo!"    
  30.  
  31.     Copyright:    Copyright © 1996-1999 by Apple Computer, Inc., All Rights Reserved.
  32.  
  33.                 You may incorporate this Apple sample source code into your program(s) without
  34.                 restriction. This Apple sample source code has been provided "AS IS" and the
  35.                 responsibility for its operation is yours. You are not permitted to redistribute
  36.                 this Apple sample source code as "Apple sample source code" after having made
  37.                 changes. If you're going to re-distribute the source, we require that you make
  38.                 it clear in the source that the code was descended from Apple sample source
  39.                 code, but that you've made changes.
  40.  
  41.     Change History (most recent first):
  42.                 7/21/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
  43.                 
  44.  
  45. */
  46.     
  47. #include <AppleEvents.h>
  48. #include <Errors.h>
  49. #include <Events.h>
  50. #include <Fonts.h>
  51. #include <Gestalt.h>
  52. #include <Memory.h>
  53. #include <Menus.h>
  54. #include <OSUtils.h>
  55. #include <QDOffscreen.h>
  56. #include <QuickDraw.h>
  57. #include <Resources.h>
  58. #include <Script.h>
  59. #include <ToolUtils.h>
  60. #include <Windows.h>
  61. #include <AEPackObject.h>
  62. #include <AERegistry.h>
  63. #include <AEObjects.h>
  64. #include <Folders.h>
  65. #include <TextEdit.h>
  66. #include <Dialogs.h>
  67.  
  68. //////////////////////////////////////////////////////////////////////////
  69. // Basic Utilities
  70.  
  71. static OSErr FindProcessByTypeAndCreator(OSType typeToFind, OSType creatorToFind, ProcessSerialNumber *processSN)
  72.     // Runs through the process list looking for the indicated application.
  73. {
  74.     OSErr err;
  75.         ProcessInfoRec infoRecToFill;
  76.         
  77.     err = noErr;
  78.     processSN->lowLongOfPSN = kNoProcess;
  79.     processSN->highLongOfPSN = kNoProcess;
  80.     infoRecToFill.processInfoLength = sizeof(ProcessInfoRec);
  81.     infoRecToFill.processName = nil;
  82.     infoRecToFill.processAppSpec = nil;
  83.     do {
  84.         err = GetNextProcess(processSN);
  85.         if (err == noErr) {
  86.             GetProcessInformation(processSN, &infoRecToFill);
  87.         }
  88.     } while ((infoRecToFill.processSignature != creatorToFind || infoRecToFill.processType != typeToFind) ||
  89.                    err != noErr);
  90.     
  91.     return(err);
  92. }
  93.  
  94. //////////////////////////////////////////////////////////////////////////
  95. // Global Types
  96.  
  97. // The snapshot file is made up of records of SnapRecord type.
  98. // An empty record (ie with name == "") is used to indicate
  99. // the end of the file.
  100.  
  101. typedef struct 
  102. {
  103.     Str63 name;
  104.     Point loc;
  105. } SnapRecord, *SnapRecordPtr, **SnapRecordHandle;
  106.  
  107.  
  108. //////////////////////////////////////////////////////////////////////////
  109. // Global Variables
  110.  
  111. // Used to tell the main event loop to quit.
  112.  
  113. static Boolean gQuit = false;
  114.  
  115. // An empty AppleEvent Descriptor.
  116.  
  117. const static AEDesc gNullDesc = {typeNull, nil};
  118.  
  119. //////////////////////////////////////////////////////////////////////////
  120. // Restoring Snapshots
  121.  
  122. static OSErr SetItemPosition(Str255 fname, Point dest, AEDesc *setDataEvent)
  123.     // Sends an AppleEvent to the targetDesc (which should target the Finder)
  124.     //  to set the position of the item whose name is fname to the position dest.
  125. {
  126.     OSErr        err;
  127.     AEDesc        fileNameDesc         = gNullDesc;
  128.     AEDesc        rootDesc             = gNullDesc;
  129.     AEDesc        propertyDescriptor     = gNullDesc;
  130.     AEDesc        objParentDesc         = gNullDesc;
  131.     AEDesc        objDesc             = gNullDesc;
  132.     AEDesc        reply                 = gNullDesc;
  133.     AEDesc        newData             = gNullDesc;
  134.     DescType    procDescData         = 'posn';
  135.  
  136.     err = AECreateDesc(typeChar, &fname[1], fname[0], &fileNameDesc);
  137.         
  138.     // Create objParentDesc to specify the parent object, ie item "xxxx" of application
  139.     if (err == noErr) {
  140.         err = CreateObjSpecifier(cObject, &rootDesc, formName, &fileNameDesc, false, &objParentDesc);
  141.     }
  142.  
  143.     // Create propertyDescriptor to hold the property specifier, ie position
  144.     if (err == noErr) {
  145.         err = AECreateDesc(typeType, &procDescData, sizeof(procDescData), &propertyDescriptor);
  146.     }
  147.     
  148.     // Create objDesc to reference the data to set, ie position of item "xxx" of application
  149.     if (err == noErr) {
  150.         err = CreateObjSpecifier(cProperty, &objParentDesc, formPropertyID, &propertyDescriptor, false, &objDesc);
  151.     }
  152.  
  153.     // Create on descriptor to hold the new data, ie the new icon position.
  154.     if (err == noErr) {
  155.         err = AECreateDesc(typeQDPoint, (void*)&dest, sizeof(dest), &newData);
  156.     }
  157.  
  158.     // Fill out the parameters, putting the objDesc into the direct object and the new data
  159.     //  into the data parameter.
  160.     if (err == noErr) {
  161.         err = AEPutParamDesc(setDataEvent, keyDirectObject, &objDesc);
  162.     }
  163.     if (err == noErr) {
  164.         err = AEPutParamDesc(setDataEvent, keyAEData, &newData);
  165.     }
  166.  
  167.     // Send the event.
  168.     if (err == noErr) {
  169.         err = AESend(setDataEvent, &reply, kAEWaitReply, kAENormalPriority, kAEDefaultTimeout, nil, nil);
  170.         
  171.         // Some code that I enable when I'm debugging.
  172.         
  173.         if (false) {
  174.             long errNum;
  175.             Str255      errStr;
  176.             DescType    junkType;
  177.             Size        realSize;
  178.             
  179.             err = AEGetParamPtr(&reply, keyErrorNumber, typeInteger, &junkType, &errNum, sizeof(errNum), &realSize);
  180.             err = AEGetParamPtr(&reply, keyErrorString, typeChar, &junkType, &errStr[1], 255, &realSize);
  181.             errStr[0] = realSize;
  182.         }
  183.     }
  184.  
  185.     // Clean up all those messy descriptors.  Don't you just love AppleEvents (-:
  186.     AEDisposeDesc(&rootDesc);
  187.     AEDisposeDesc(&fileNameDesc);
  188.     AEDisposeDesc(&objParentDesc);
  189.     AEDisposeDesc(&propertyDescriptor);
  190.     AEDisposeDesc(&objDesc);
  191.     AEDisposeDesc(&newData);
  192.     AEDisposeDesc(&reply);
  193.     
  194.     return err;
  195. }
  196.  
  197. static OSErr RestoreSnapshot (FSSpec snapFss)
  198.     // Restore the snapshot file specified by snapFss.
  199. {
  200.     OSErr                err;
  201.     ProcessSerialNumber finderPSN;
  202.     AEDesc                targetDesc         = gNullDesc;
  203.     AEDesc                setDataEvent     = gNullDesc;
  204.     short                snapFileRef;
  205.     Boolean             done;
  206.     SnapRecord            aSnapRecord;
  207.     long                byteCount;
  208.  
  209.     snapFileRef = 0;
  210.     
  211.     // Find the Finder's ProcessSerialNumber and create the targetDesc for it.
  212.     err = FindProcessByTypeAndCreator('FNDR', 'MACS', &finderPSN);
  213.     if (err == noErr) {
  214.         err = AECreateDesc(typeProcessSerialNumber, (Ptr)&finderPSN, sizeof(finderPSN), &targetDesc);
  215.     }
  216.     // Create the AppleEvent.
  217.     if (err == noErr) {
  218.             err = AECreateAppleEvent(kAECoreSuite, kAESetData, &targetDesc,
  219.                                                                 kAutoGenerateReturnID, kAnyTransactionID, &setDataEvent);
  220.     }    
  221.     
  222.     // Open the file.
  223.     if (err == noErr) {
  224.         err = FSpOpenDF(&snapFss, fsRdPerm, &snapFileRef);
  225.     }
  226.     if (err == noErr) {
  227.         
  228.         // Read the records in the file, repositioning the icons as we go.
  229.         done = false;
  230.         do {
  231.             byteCount = sizeof(SnapRecord);
  232.             err = FSRead(snapFileRef, &byteCount, (void*) &aSnapRecord);
  233.             
  234.             if (err == noErr) {
  235.                 // We're done if we hit the empty string.
  236.                 done = (aSnapRecord.name[0] == 0);
  237.                 
  238.                 if (!done) {
  239.                     // Reposition the icon.
  240.                     err = SetItemPosition(aSnapRecord.name, aSnapRecord.loc, &setDataEvent);
  241.                 }
  242.             }
  243.         } while (!done);
  244.     }
  245.     
  246.     if (err == eofErr) {
  247.         err = noErr;
  248.     }
  249.  
  250.     // clean up
  251.     if (snapFileRef != 0) {
  252.         (void) FSClose(snapFileRef);
  253.     }
  254.     AEDisposeDesc(&setDataEvent);
  255.     AEDisposeDesc(&targetDesc);
  256.         
  257.     return err;
  258. }
  259.  
  260. //////////////////////////////////////////////////////////////////////////
  261. // Creating Snapshots
  262.  
  263. static OSErr WriteFileRecord(short snapFileRef, Str63 itemName, Point itemPosition)
  264.     // Add a new record to the snapshot file.
  265. {
  266.     OSErr        err;
  267.     SnapRecord    aSnapRecord;
  268.     long        byteCount;
  269.     
  270.     BlockMoveData(itemName, aSnapRecord.name, sizeof(aSnapRecord.name));
  271.     aSnapRecord.loc = itemPosition;
  272.     
  273.     byteCount = sizeof(SnapRecord);
  274.     err = FSWrite(snapFileRef, &byteCount, (void*) &aSnapRecord);
  275.     
  276.     return err;
  277. }
  278.  
  279. static OSErr CreateSnapshotFile(FSSpec snapFss)
  280.     // Add the positions for the icons on the desktop to the snapshot file snapFss.
  281. {
  282.     OSErr         err;
  283.     short        snapFileRef;
  284.     short        deskVRefNum;
  285.     long        deskDirID;
  286.     CInfoPBRec    pb;
  287.     short        fileIndex;
  288.     Point        folderOrigin;
  289.     Point        itemPosition;
  290.     Str63        itemName;
  291.     UInt32        systemVersion;
  292.  
  293.     snapFileRef = 0;
  294.     
  295.     // Find the desktop folder.
  296.     err = FindFolder(kOnSystemDisk, kDesktopFolderType, true, &deskVRefNum, &deskDirID);
  297.     
  298.     // Get the origin for the desktop folder.
  299.     pb.dirInfo.ioNamePtr = nil;
  300.     pb.dirInfo.ioDrDirID = deskDirID;
  301.     pb.dirInfo.ioVRefNum = deskVRefNum;
  302.     pb.dirInfo.ioFDirIndex = -1;        // get information about ioDirID
  303.     err = PBGetCatInfoSync(&pb);
  304.     if (err == noErr) {
  305.         folderOrigin.h = 0;
  306.         folderOrigin.v = 0;
  307.         if (Gestalt(gestaltSystemVersion, (long *) &systemVersion) != noErr || systemVersion < 0x0800) {
  308.             // Evil fudge factor is needed for Finder 7.x.  Finder 8.0 does not fudge.
  309.             folderOrigin.v = folderOrigin.v - 20;
  310.         }
  311.     }
  312.  
  313.     // Open up the snapshot file.
  314.     if (err == noErr) {
  315.         err = FSpOpenDF(&snapFss, fsRdWrPerm, &snapFileRef);
  316.     }
  317.  
  318.     // Loop through each file in the folder, adding it to the snapshot file.
  319.     if (err == noErr) {
  320.         fileIndex = 1;
  321.         do {
  322.                 pb.dirInfo.ioNamePtr = (StringPtr) itemName;
  323.                 pb.dirInfo.ioDrDirID = deskDirID;
  324.                 pb.dirInfo.ioVRefNum = deskVRefNum;
  325.                 pb.dirInfo.ioFDirIndex = fileIndex;
  326.                 err = PBGetCatInfoSync(&pb);
  327.                 if (err == noErr) {
  328.                     itemPosition = pb.hFileInfo.ioFlFndrInfo.fdLocation;
  329.                     SubPt(folderOrigin, &itemPosition);
  330.                     err = WriteFileRecord(snapFileRef, itemName, itemPosition);
  331.                 }
  332.                 fileIndex += 1;
  333.         } while (err == noErr);
  334.         
  335.         // Write the sentinel to the end of the file.
  336.         if (err == fnfErr) {
  337.             itemName[0] = 0;
  338.             itemPosition.h = 0;
  339.             itemPosition.v = 0;
  340.             err = WriteFileRecord(snapFileRef, itemName, itemPosition);
  341.         }
  342.     }
  343.         
  344.     // Clean up.
  345.     if (snapFileRef != 0) {
  346.         (void) FSClose(snapFileRef);
  347.     }
  348.         
  349.     return err;
  350. }
  351.  
  352. //////////////////////////////////////////////////////////////////////////
  353. // Main Line
  354.  
  355. static void InitToolbox()
  356.     // Standard Macintosh toolbox init.
  357. {
  358.     InitGraf(&qd.thePort);
  359.     InitFonts();
  360.     InitWindows();
  361.     InitMenus();
  362.     TEInit();
  363.     InitDialogs(nil);
  364.     MaxApplZone();
  365.     
  366.     MoreMasters();
  367.     MoreMasters();
  368.     MoreMasters();
  369.  
  370.     InitCursor();
  371.     FlushEvents(0, everyEvent);    
  372. }
  373.  
  374. void main(void)
  375.     // The application's main entry point.
  376. {
  377.     OSErr     err;
  378.     FSSpec    snapFss;
  379.     long    gestaltResponse;
  380.  
  381.     // First, a quick check to make sure we have Scriptable Finder.  If we don't
  382.     //  we bail quickly.
  383.     
  384.     if ((Gestalt(gestaltFinderAttr, &gestaltResponse) != noErr) || ((gestaltResponse & (1 << gestaltOSLCompliantFinder)) == 0)) {
  385.         DebugStr("\pWhoops, no Scriptable Finder.");
  386.         ExitToShell();
  387.     }
  388.  
  389.     // Now bring up the standard Mac toolbox.
  390.     InitToolbox();
  391.     
  392.     // Find the Preferences folder.
  393.     err = FindFolder(kOnSystemDisk, kPreferencesFolderType, false, &(snapFss.vRefNum), &(snapFss.parID));
  394.  
  395.     if (err == noErr) {
  396.  
  397.         // Open the snapshot file in the Preferences folder.
  398.         //  Should get this from a resource, of course.
  399.         
  400.         (void) FSMakeFSSpec(snapFss.vRefNum, snapFss.parID, "\pDesktop Snap", &snapFss);
  401.         err = FSpCreate(&snapFss, 'FRøG', 'FRøG', 0);
  402.         
  403.         if (err == dupFNErr) {                            // If we already have a snapshot file,
  404.             err = RestoreSnapshot(snapFss);                //  restore icon positions,
  405.         } else if (err == noErr) {                        // otherwise make a snapshot file.
  406.             // Create the snapshot file for the desktop
  407.             err = CreateSnapshotFile(snapFss);
  408.         }
  409.     }
  410.     
  411.     if (err != noErr) {
  412.         DebugStr("\pSnapshotter failed.");
  413.     }
  414. }
  415.